import { clone } from "lodash-es";

export type ColorMeta = [number, number];
export type PositionMeta = [number, number];
export type DataDiff = {
    position: PositionMeta;
    /** 颜色关系为纯替换关系 */
    diff: [ColorMeta, ColorMeta];
};

export interface MetaObject<T> {
    /** 用户唯一标识 */
    user: string;
    /** 操作的类型 */
    type: "default" | "combined";
    time: number;
    /** 数据更替数组,position 唯一 */
    change: T;
    /** 简易的指令，用于一些微操控 */
    command?: any;
}

export class MetaCombine {
    private changeMap = new Map<string, number>();
    change: DataDiff[] = [];
    constructor() {}
    combine(value: Meta) {
        value.change.forEach(({ position, diff }) => {
            // ! 请勿改变 position 和 diff 变量
            const key = position.join(",");
            if (this.changeMap.has(key)) {
                const index = this.changeMap.get(key)!;
                const data = this.change[index];
                data.diff = [data.diff[0], diff[1]];
            } else {
                const index = this.change.push({
                    position: clone(position),
                    diff: clone(diff),
                });
                this.changeMap.set(key, index - 1);
            }
        });
    }
}

/** 元数据，用于记录渲染过程 */
export class Meta implements MetaObject<DataDiff[]> {
    user;
    type;
    time;
    change;
    /** 可以被直接 JSON.stringify */

    constructor({
        user,
        type = "default",
        time = new Date().getTime(),
        change = [] as DataDiff[],
    }: Partial<MetaObject<DataDiff[]>>) {
        this.user = user ?? "";
        this.type = type;
        this.time = time;
        this.change = change;
    }
    /** 设置这个 Meta 将会如何被合并到集合中,不改变本身
     * */
    addTo(Collection: MetaCombine) {
        Collection.combine(this);
    }
}
